home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 1 / Amiga Tools.iso / disk-tools / hd-tools / scsi_tape / source.lha / tape / x < prev   
Encoding:
Text File  |  1991-11-16  |  10.3 KB  |  494 lines

  1.  
  2. /*
  3.  *  TAPE-HANDLER.C
  4.  *
  5.  *  tape interface
  6.  *
  7.  *  TAPE:flags
  8.  *
  9.  *     r    rewind
  10.  *     a    append
  11.  */
  12.  
  13. #include "defs.h"
  14.  
  15. #define SwapBufs(chan) { char *t1 = chan->ch_Buf1; long l1 = chan->ch_BufLen1; \
  16.              chan->ch_Buf1 = chan->ch_Buf2; chan->ch_BufLen1 = chan->ch_BufLen2; \
  17.              chan->ch_Buf2 = t1;  chan->ch_BufLen2 = l1;                 \
  18.             }
  19.  
  20. Prototype int main(short, char **);
  21. Prototype void    myexit(void);
  22. Prototype void    MkDevice(char *);
  23. Prototype void    DelDevice(void);
  24. Prototype void    *DosAllocMem(long);
  25. Prototype void    DosFree(void *);
  26. Prototype void    HandleDosPacket(DosPacket *, short);
  27. Prototype void    HandleReturnedRequest(Chan *);
  28. Prototype void    ReturnPacket(DosPacket *);
  29. Prototype void    HoldPacket(List *, DosPacket *);
  30. Prototype void    RetryWaitingPacket(List *);
  31.  
  32. Prototype MsgPort   *IoSink;
  33. Prototype MsgPort   *DosRetry;
  34. Prototype short     DDebug;
  35. Prototype List        ChanList;
  36.  
  37. MsgPort *IoSink;
  38. MsgPort *DosRetry;
  39. char    *DeviceName = "scsi.device";
  40. long    UnitNo = -1;
  41. short    DDebug;
  42. List    ChanList;
  43.  
  44. ubyte rewind_cmd[]   = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
  45. ubyte append_cmd[]   = { 0x11, 0x03, 0x00, 0x00, 0x00, 0x00 };
  46. ubyte filemark_cmd[] = { 0x10, 0x00, 0x00, 0x00, 0x01, 0x00 };
  47.  
  48. extern struct DosLibrary *DOSBase;
  49.  
  50. main(ac, av)
  51. short ac;
  52. char *av[];
  53. {
  54.     long sinkMask;
  55.     long retryMask;
  56.     long mask;
  57.  
  58.     NewList(&ChanList);
  59.     if (ac == 1) {
  60.     printf("tape-handler device_name [-D scsi.device] -U unit\n");
  61.     exit(0);
  62.     }
  63.     IoSink = CreatePort(NULL, 0);
  64.     DosRetry = CreatePort(NULL, 0);
  65.  
  66.     sinkMask = 1 << IoSink->mp_SigBit;
  67.     retryMask = 1 << DosRetry->mp_SigBit;
  68.  
  69.     {
  70.     short i;
  71.     for (i = 2; i < ac; ++i) {
  72.         char *ptr = av[i];
  73.         if (*ptr != '-')
  74.         continue;
  75.         ptr += 2;
  76.         switch(ptr[-1]) {
  77.         case 'D':
  78.         DeviceName = (*ptr) ? ptr : av[++i];
  79.         break;
  80.         case 'U':
  81.         UnitNo = strtol((*ptr) ? ptr : av[++i], NULL, 0);
  82.         break;
  83.         }
  84.     }
  85.     }
  86.     if (DeviceName == NULL || UnitNo == -1) {
  87.     puts("run <nil: >nil: tape-handler <devname> -D<device> -U<unit>");
  88.     exit(20);
  89.     }
  90.     MkDevice(av[1]);
  91.  
  92.     for (;;) {
  93.     Message *msg;
  94.  
  95.     while (msg = GetMsg(DosRetry))
  96.         HandleDosPacket((DosPacket *)msg->mn_Node.ln_Name, 1);
  97.     while (msg = GetMsg(IoSink)) {
  98.         if (msg->mn_Node.ln_Type = NT_MESSAGE)
  99.         HandleDosPacket((DosPacket *)msg->mn_Node.ln_Name, 0);
  100.         else
  101.         HandleReturnedRequest((Chan *)msg->mn_Node.ln_Name);
  102.     }
  103.     mask = Wait(SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E | sinkMask | retryMask);
  104.     if (mask & (SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D)) {
  105.         if (GetHead(&ChanList) == NULL)
  106.         break;
  107.     }
  108.     }
  109.     return(0);
  110. }
  111.  
  112. void
  113. myexit()
  114. {
  115.     void *z = NULL;
  116.  
  117.     DelDevice();
  118.     if (IoSink) {
  119.     DeletePort(IoSink);
  120.     IoSink = z;
  121.     }
  122.     if (DosRetry) {
  123.     DeletePort(DosRetry);
  124.     DosRetry = z;
  125.     }
  126. }
  127.  
  128. void
  129. HandleDosPacket(pkt, retry)
  130. DosPacket *pkt;
  131. short retry;
  132. {
  133.     if (retry == 0) {
  134.     pkt->dp_Res1 = 0;
  135.     pkt->dp_Res2 = 0;
  136.     }
  137.  
  138.     switch(pkt->dp_Type) {
  139.     case ACTION_FINDUPDATE:    /*  FileHandle,Lock,Name    Bool        */
  140.     case ACTION_FINDINPUT:    /*  FileHandle,Lock,Name    Bool        */
  141.     case ACTION_FINDOUTPUT:    /*  FileHandle,Lock,Name    Bool        */
  142.     /*
  143.      *  attempt to open tape scsi device
  144.      */
  145.  
  146.     {
  147.         FileHandle *fh = (FileHandle *)BADDR(pkt->dp_Arg1);
  148.         Chan *chan = AllocMem(sizeof(Chan), MEMF_PUBLIC | MEMF_CLEAR);
  149.         int error;
  150.  
  151.         NewList(&chan->ch_PktList);
  152.         {
  153.         ubyte *ptr = (ubyte *)BADDR(pkt->dp_Arg3);
  154.         int len;
  155.  
  156.         for (len = *ptr; len > 0; --len) {
  157.             if (ptr[len] == ':')
  158.             break;
  159.             switch(ptr[len] | 0x20) {
  160.             case 'a':   /*  append  */
  161.             chan->ch_Flags |= CHANF_APPEND | CHANF_REWIND;
  162.             break;
  163.             case 'r':   /*  rewind  */
  164.             chan->ch_Flags |= CHANF_REWIND;
  165.             break;
  166.             }
  167.         }
  168.         }
  169.         chan->ch_DeviceName = DeviceName;
  170.         chan->ch_UnitNo    = UnitNo;
  171.         chan->ch_BufSize    = 32768;
  172.         chan->ch_Buf1    = AllocMem(chan->ch_BufSize, MEMF_PUBLIC);
  173.         chan->ch_Buf2    = AllocMem(chan->ch_BufSize, MEMF_PUBLIC);
  174.  
  175.         error = SCSIOpen(chan);
  176.  
  177.         if (error == 0 && chan->ch_Flags & CHANF_REWIND)
  178.         error = DoSCSI(chan, rewind_cmd, NULL, 0, SCSIF_READ, NULL);
  179.  
  180.         if (error == 0 && chan->ch_Flags & CHANF_APPEND)
  181.         error = DoSCSI(chan, append_cmd, NULL, 0, SCSIF_READ, NULL);
  182.  
  183.         if (error == 0) {
  184.         fh->fh_Port = (MsgPort *)DOS_FALSE;
  185.         fh->fh_Arg1 = chan;
  186.         pkt->dp_Res1 = DOS_TRUE;
  187.         pkt->dp_Res2 = 0;
  188.         AddTail(&ChanList, &chan->ch_Node);
  189.         } else {
  190.         SCSIClose(chan);
  191.         fh->fh_Port = (MsgPort *)DOS_FALSE;
  192.         fh->fh_Arg1 = NULL;
  193.         pkt->dp_Res2 = error;
  194.         pkt->dp_Res1 = DOS_FALSE;
  195.         FreeMem(chan->ch_Buf1, chan->ch_BufSize);
  196.         FreeMem(chan->ch_Buf2, chan->ch_BufSize);
  197.         FreeMem(chan, sizeof(Chan));
  198.         }
  199.     }
  200.     ReturnPacket(pkt);
  201.     break;
  202.     case ACTION_READ:        /*  FHArg1,CPTRBuffer,Length    ActLength   */
  203.     /*
  204.      *  read data
  205.      */
  206.  
  207.     {
  208.         Chan *chan = (Chan *)pkt->dp_Arg1;
  209.         long n;
  210.         long bytes = pkt->dp_Arg3 - pkt->dp_Res1;
  211.  
  212.  
  213.         /*
  214.          *    copy from Buf1
  215.          */
  216.  
  217.         if (n = chan->ch_BufLen1) {
  218.         if (n > bytes)
  219.             n = bytes;
  220.         CopyMem(chan->ch_Buf1 + chan->ch_BufIdx1, (void *)((long)pkt->dp_Arg2 + pkt->dp_Res1), n);
  221.         pkt->dp_Res1 += n;
  222.         bytes         -= n;
  223.         chan->ch_BufLen1 -= n;
  224.         chan->ch_BufIdx1 += n;
  225.         }
  226.  
  227.         /*
  228.          *    return or requeue DOS request as indicated
  229.          */
  230.  
  231.         if (bytes == 0 || (chan->ch_Flags & CHANF_EOF))
  232.         ReturnPacket(pkt);
  233.         else
  234.         HoldPacket(&chan->ch_PktList, pkt);
  235.  
  236.         /*
  237.          *    if Buf1 empty and Buf2 not, move'm in
  238.          */
  239.  
  240.         if (chan->ch_BufLen1 == 0 && chan->ch_BufLen2) {
  241.         SwapBufs(chan);
  242.         chan->ch_BufIdx1 = 0;
  243.         RetryWaitingPacket(&chan->ch_PktList);
  244.         }
  245.  
  246.         /*
  247.          *    attempt to read next buffer in while program processing
  248.          *    first.    Or, if buffer is full, swap into buf1
  249.          */
  250.  
  251.         if ((chan->ch_Flags & (CHANF_EOF|CHANF_IOSIP)) == 0 && chan->ch_BufLen2 == 0) {
  252.         char read_cmd[6] = { 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 };
  253.         SendSCSI(chan, read_cmd, chan->ch_Buf2, chan->ch_BufSize, SCSIF_READ);
  254.         }
  255.     }
  256.     break;
  257.     case ACTION_WRITE:
  258.     /*
  259.      *  write data
  260.      */
  261.  
  262.     {
  263.         Chan *chan = (Chan *)pkt->dp_Arg1;
  264.         long n;
  265.         long bytes = pkt->dp_Arg3 - pkt->dp_Res1;
  266.  
  267.         /*
  268.          *    copy as much as possible to Buf1
  269.          */
  270.  
  271.         chan->ch_Flags |= CHANF_WRITE;
  272.         if (n = chan->ch_BufSize - chan->ch_BufLen1) {
  273.         if (n > bytes)
  274.             n = bytes;
  275.         CopyMem((void *)((long)pkt->dp_Arg2 + pkt->dp_Res1), (void *)(chan->ch_Buf1 + chan->ch_BufLen1), n);
  276.         pkt->dp_Res1 += n;
  277.         bytes         -= n;
  278.         chan->ch_BufLen1 += n;
  279.         }
  280.  
  281.         /*
  282.          *    return or requeue DOS request as indicated
  283.          */
  284.  
  285.         if (bytes == 0 || (chan->ch_Flags & CHANF_EOF))
  286.         ReturnPacket(pkt);
  287.         else
  288.         HoldPacket(&chan->ch_PktList, pkt);
  289.  
  290.         /*
  291.          *    If buffer is full then transfer to Buf2 and start write
  292.          */
  293.  
  294.         if (chan->ch_BufLen1 == chan->ch_BufSize && chan->ch_BufLen2 == 0) {
  295.         char write_cmd[6] = { 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00 };
  296.         SendSCSI(chan, write_cmd, chan->ch_Buf1, chan->ch_BufLen1, SCSIF_WRITE);
  297.         SwapBufs(chan);
  298.         RetryWaitingPacket(&chan->ch_PktList);
  299.         }
  300.     }
  301.     break;
  302.     case ACTION_END:
  303.     {
  304.         Chan *chan = (Chan *)pkt->dp_Arg1;
  305.  
  306.         pkt->dp_Res2 = 0;
  307.         pkt->dp_Res1 = DOS_TRUE;
  308.         ReturnPacket(pkt);
  309.  
  310.         Remove(&chan->ch_Node);
  311.         if (chan->ch_Flags & CHANF_WRITE) {
  312.         char write_cmd[6] = { 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00 };
  313.  
  314.         if (chan->ch_Flags & CHANF_IOSIP)
  315.             WaitSCSI(chan, NULL);
  316.         if (chan->ch_BufLen1) {
  317.             long extra = 512 - (chan->ch_BufLen1 & 511);
  318.  
  319.             if (extra == 512)
  320.             extra = 0;
  321.             if (extra)
  322.             clrmem(chan->ch_Buf1 + chan->ch_BufLen1, extra);
  323.             DoSCSI(chan, write_cmd, chan->ch_Buf1, chan->ch_BufLen1 + extra, SCSIF_WRITE, NULL);
  324.         }
  325.         DoSCSI(chan, filemark_cmd, NULL, 0, SCSIF_READ, NULL);
  326.         }
  327.         SCSIClose(chan);
  328.         FreeMem(chan->ch_Buf1, chan->ch_BufSize);
  329.         FreeMem(chan->ch_Buf2, chan->ch_BufSize);
  330.         FreeMem(chan, sizeof(Chan));
  331.     }
  332.     break;
  333.     case ACTION_DIE:
  334.     default:
  335.     pkt->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  336.     pkt->dp_Res1 = DOS_FALSE;
  337.     ReturnPacket(pkt);
  338.     break;
  339.     }
  340. }
  341.  
  342. void
  343. HandleReturnedRequest(chan)
  344. Chan *chan;
  345. {
  346.     long len;
  347.     int error;
  348.  
  349.     chan->ch_Flags &= ~CHANF_IOSIP;
  350.     error = WaitSCSI(chan, &len);
  351.  
  352.     if (chan->ch_Flags & CHANF_WRITE) {
  353.     /*
  354.      *  if write returned buffer space now freed up
  355.      */
  356.  
  357.     chan->ch_BufLen2 = 0;
  358.     RetryWaitingPacket(&chan->ch_PktList);
  359.     } else {
  360.     /*
  361.      *  if read returned, data now available and can queue up another
  362.      *  read, in fact!
  363.      */
  364.  
  365.     switch(error) {
  366.     case 0x80:
  367.         chan->ch_Flags |= CHANF_EOF;
  368.         /* fall through */
  369.     case 0:
  370.         break;
  371.     default:
  372.         len = 0;
  373.     }
  374.     chan->ch_BufLen2 = len;
  375.  
  376.     if (chan->ch_BufLen1 == 0 && chan->ch_BufLen2) {
  377.         SwapBufs(chan);
  378.         chan->ch_BufIdx1 = 0;
  379.         RetryWaitingPacket(&chan->ch_PktList);
  380.     }
  381.     RetryWaitingPacket(&chan->ch_PktList);
  382.     }
  383. }
  384.  
  385. DosList *Dl;
  386.  
  387. void
  388. MkDevice(devName)
  389. char *devName;
  390. {
  391.     DosList *dl;
  392.     RootNode *root;
  393.     DosInfo *info;
  394.  
  395.     Dl = dl = (struct DosList *)DosAllocMem(sizeof(struct DosList)+strlen(devName)+2);
  396.     strcpy((char *)(dl+1) + 1, devName);
  397.     *(char *)(dl + 1) = strlen(devName);
  398.     dl->dol_Type = DLT_DEVICE;
  399.     dl->dol_Task = IoSink;
  400.     dl->dol_Name = MKBADDR((char *)(dl+1));
  401.  
  402.     Forbid();
  403.     root  = (struct RootNode *)DOSBase->dl_Root;
  404.     info  = (struct DosInfo  *)BADDR(root->rn_Info);
  405.     dl->dol_Next = info->di_DevInfo;
  406.     info->di_DevInfo = MKBADDR(dl);
  407.     Permit();
  408. }
  409.  
  410. void
  411. DelDevice()
  412. {
  413.     DosList *dl;
  414.     DosInfo *info;
  415.     RootNode *root;
  416.     DosList *dls;
  417.     BPTR    *bpp;
  418.  
  419.     if (dl = Dl) {
  420.     Forbid();
  421.     root  = (struct RootNode *)DOSBase->dl_Root;
  422.     info  = (struct DosInfo  *)BADDR(root->rn_Info);
  423.  
  424.     for (bpp = &info->di_DevInfo; dls = BADDR(*bpp); bpp = &dls->dol_Next) {
  425.         if (dls == dl)
  426.         break;
  427.     }
  428.     if (dls == dl) {
  429.         *bpp = dls->dol_Next;
  430.     } else {
  431.         ;
  432.     }
  433.     Permit();
  434.     DosFree(dl);
  435.     Dl = NULL;
  436.     }
  437. }
  438.  
  439. void *
  440. DosAllocMem(bytes)
  441. long bytes;
  442. {
  443.     long *ptr;
  444.  
  445.     bytes += 4;
  446.  
  447.     if (ptr = AllocMem(bytes, MEMF_PUBLIC | MEMF_CLEAR)) {
  448.     *ptr++ = bytes;
  449.     return((void *)ptr);
  450.     }
  451. }
  452.  
  453. void
  454. DosFree(vptr)
  455. void *vptr;
  456. {
  457.     long *ptr = vptr;
  458.     --ptr;
  459.     FreeMem(ptr, *ptr);
  460. }
  461.  
  462. void
  463. ReturnPacket(pkt)
  464. DosPacket *pkt;
  465. {
  466.     Message *msg;
  467.     MsgPort *replyPort;
  468.  
  469.     replyPort     = pkt->dp_Port;
  470.     msg      = pkt->dp_Link;
  471.     pkt->dp_Port = IoSink;
  472.     msg->mn_Node.ln_Name = (char *)pkt;
  473.     PutMsg(replyPort, msg);
  474. }
  475.  
  476. void
  477. HoldPacket(list, pkt)
  478. List *list;
  479. DosPacket *pkt;
  480. {
  481.     AddTail(list, &pkt->dp_Link->mn_Node);
  482. }
  483.  
  484. void
  485. RetryWaitingPacket(list)
  486. List *list;
  487. {
  488.     Message *msg;
  489.  
  490.     while (msg = RemHead(list))
  491.     PutMsg(DosRetry, msg);
  492. }
  493.  
  494.